use std::env;

mod utils;
mod report;
mod fsync;

use utils::Option;

#[derive(Debug)]
struct Task {
    opt:Option,
    n_count:report::Count,
}
impl fsync::Events for Task {
    fn on_join(&mut self) {
        self.n_count.add_join(1);
    }
    fn on_update(&mut self) {
        self.n_count.add_update(1);
    }
    fn on_remove(&mut self) {
        self.n_count.add_remove(1);
    }
    fn on_push(&mut self) {
        self.n_count.add_push(1);
    }
    fn on_error(&mut self, msg:String) {
        if ! self.opt.is_silent {
            report::error(msg)
        }
        if self.opt.terminate_if_sync_error {
            panic!()
        }
    }
}
impl Task {
    fn new(opt:Option) -> Task {
        Task {
            opt, n_count: report::Count::new(),
        }
    }
    fn start(opt:Option) {
        let mut task = Task::new(opt.clone());
        let paths = task.opt.paths.clone();
        if paths.len() > 1 {
            let path_from = &paths[0];
            for path_to in &paths[1..] {
                fsync::fsync(path_from, path_to, &opt, &mut task);
            }
            if ! task.opt.is_silent {
                report::result(&task.n_count)
            }
        } else {
            report::error_and_quit(format!("must have <dir-from> and a <dir-to>"));
        }
    }
}

fn main() {
    let args:Vec<String> = env::args().collect();
    if args.len() > 1 {
        let mut opt = Option::new();
        opt.allow_recurive_dir = true;
        opt.is_silent = false;
        opt.terminate_if_sync_error = false;
        opt.parse_args(&args[1..]);
        Task::start(opt);
    } else {
        report::usage();
    }
}
